﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using JustinAngel.Neurons.Framework.Helpers;
using JustinAngel.Neurons.Framework.Messages;
using JustinAngel.Neurons.Framework.Navigation;
using JustinAngel.Neurons.Framework.Services;
using JustinAngel.Neurons.Services;
using JustinAngel.UnitedNationsNews.AppCore;
using JustinAngel.UnitedNationsNews.Framework;
using JustinAngel.UnitedNationsNews.ServerModel;
using JustinAngel.UnitedNationsNews.Services;
using Microsoft.Phone.Shell;
using System.Linq;

namespace JustinAngel.Neurons.Framework
{
    public class VViewModelBase : ViewModelBase
    {
        public VViewModelBase()
        {
            MessengerInstance = IoC.Get<IMessenger>();
            DataService = IoC.Get<IDataService>();

            MessengerInstance.Register<ApplicationActivatedMessage>(this, msg => CheckOnApplicationActivated());
            CheckOnApplicationActivated();
            MessengerInstance.Register<ApplicationDeactivatedMessage>(this, OnApplicationDeactivated);
        }

        private string _state;
        public string CurrentStateName
        {
            get { return _state; }
            set
            {
                _state = value;
                this.RaisePropertyChanged(() => CurrentStateName);
            }
        }

        protected void RaisePropertyChanged<T>(Expression<Func<T>> property)
        {
            RaisePropertyChanged(property.GetMemberName());
        }

        protected void RaisePropertyChangedAndUpdateVSM<T>(Expression<Func<T>> property, bool value)
        {
            var propName = property.GetMemberName();
            RaisePropertyChanged(propName);

            if (value)
            {
                CurrentStateName = propName;
            }
            else
            {
                CurrentStateName = "Not" + propName;
            }
        }

        public bool IsInEmulator
        {
            get
            {
                if (!IsInDesignMode)
                {
                    return IoC.Get<IDeviceHelper>().GetIsInEmulator();
                }
                else
                {
                    return false;
                }
            }
        }

        private object _data;
        public object Data
        {
            get { return _data; }
            set
            {
                _data = value;
                OnDataSet();
            }
        }

        public virtual void OnDataSet() { }

        public void BeginInvokeOnUIThreadAtEndOfQueue(Action action)
        {
            var Dispatcher = Deployment.Current.Dispatcher;
            Dispatcher.BeginInvoke(action);
        }


        public void BeginInvokeOnUIThread(Action action)
        {
            var Dispatcher = Deployment.Current.Dispatcher;
            if (Dispatcher.CheckAccess() == false)
            {
                Deployment.Current.Dispatcher.BeginInvoke(action);
            }
            else
            {
                action();
            }
        }

        [IgnoreDataMember]
        public IDataService DataService { get; set; }

        public void WithRootModel(Action<RootModel> action)
        {
            DataService.WithRootModel(action);
        }

        public virtual void OnNavigatedFrom(NavigationEventArgs navigationEventArgs)
        {
        }

        public virtual void OnNavigatedTo(NavigationEventArgs navigationEventArgs)
        {

        }


        protected virtual void OnApplicationDeactivated(ApplicationDeactivatedMessage obj)
        {
            if (IsAutomaticallyTombstoneAndRestoreViewModel)
            {
                PhoneApplicationService.Current.State[this.GetType().Name + ".Data"] = SerializationHelper.ToJsonString(this.Data);
            }
        }

        protected virtual void CheckOnApplicationActivated()
        {
            if (IsAutomaticallyTombstoneAndRestoreViewModel
                && PhoneApplicationService.Current.State.ContainsKey(this.GetType().Name + ".Data"))
            {
                var jsonString = (string) PhoneApplicationService.Current.State[this.GetType().Name + ".Data"];
                this.Data = SerializationHelper.FromJsonString(jsonString, AutomaticallyTombstoneAndRestoreViewModelType);
            }
        }

        protected void WriteStateForProperty<T>(string properyName, T value)
        {
            PhoneApplicationService.Current.State[this.GetType().Name + "." + properyName] = 
                SerializationHelper.ToJsonString(value);
        }

        protected T ReadStateForProperty<T>(string propertyName)
        {
            var returnValue = (T) SerializationHelper.FromJsonString(
                (string) PhoneApplicationService.Current.State[this.GetType().Name + "." + propertyName], typeof(T));
            PhoneApplicationService.Current.State.Remove(this.GetType().Name + "." + propertyName);
            return returnValue;
        }

        protected bool CanReadStateForProperty(string propertyName)
        {
            return PhoneApplicationService.Current.State.ContainsKey(this.GetType().Name + "." + propertyName);
        }

        /// <summary>
        /// Gets a value indicating whether or not the entire Data property will be persisted and restored during Tombstoning. 
        /// </summary>
        protected virtual bool IsAutomaticallyTombstoneAndRestoreViewModel
        {
            get { return false; }
        }

        /// <summary>
        /// Gets the type of the Data property for deserialization on auto tombstoning. 
        /// </summary>
        protected virtual Type AutomaticallyTombstoneAndRestoreViewModelType
        {
            get { return null;  }
        }

        public virtual void OnBackkeyPress(CancelEventArgs cancelEventArgs)
        {

        }

        public IShareableOnSocialNetworks ShareableOnSocialNetwroks
        {
            get
            {
                if (this is IShareableOnSocialNetworks)
                    return (IShareableOnSocialNetworks) this;
                else if (this.Data is IShareableOnSocialNetworks)
                    return (IShareableOnSocialNetworks) this.Data;
                else
                    throw new Exception(this.GetType().Name + " does not support social network sharing");
            }
        }

        public ICommand ShareOnTwitter
        {
            get
            {
                return new RelayCommand(() => 
                    IoC.Get<ISocialShareService>().ShareOnTwitter(ShareableOnSocialNetwroks));
            }
        }

        public ICommand ShareOnFacebook
        {
            get
            {
                return new RelayCommand(() =>
                    IoC.Get<ISocialShareService>().ShareOnFacebook(ShareableOnSocialNetwroks));
            }
        }

        public ICommand ShareViaEmail
        {
            get
            {
                return new RelayCommand(() =>
                    IoC.Get<ISocialShareService>().ShareViaEmail(ShareableOnSocialNetwroks));
            }
        }

        public ICommand SendEmailToDeveloper
        {
            get
            {
                return new RelayCommand(() =>
                    IoC.Get<ITaskInvoker>().SendEmail(
                        "J@JustinAngel.net",
                        "United Nations News V1.0 feedback",
                        "Hi Justin, I'm using United Nations News V1.0 and I'd just like to say that..."));
            }
        }

        public ICommand GoToWebsite
        {
            get
            {
                return new RelayCommand<string>((arg) =>
                    MessengerInstance.Send(new NavigateToMessage(PageSources.WebBrowserPage, new Uri(arg, UriKind.Absolute))));
            }
        }

        protected bool IsAttachedToViewAsDataContext { get; set; } 

        public virtual void OnAfterAttachedToViewAsDataContext()
        {
            IsAttachedToViewAsDataContext = true; 
        }
    }
}
